package io.zjw.testblelib

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothAdapter.LeScanCallback
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.location.LocationManager
import android.os.*
import android.support.annotation.RequiresApi
import android.support.design.widget.BottomSheetDialog
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v4.content.PermissionChecker
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.CardView
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.LinearSnapHelper
import android.support.v7.widget.RecyclerView
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Log
import android.view.*
import android.view.animation.AnimationUtils
import android.view.inputmethod.InputMethodManager
import android.widget.*
import cn.jesse.nativelogger.Logger
import cn.jesse.nativelogger.NLogger
import cn.jesse.nativelogger.logger.LoggerLevel
import com.alibaba.fastjson.JSONArray
import com.github.mikephil.charting.charts.LineChart
import com.yuanxu.ecg .L
import io.mega.megablelib.*
import io.mega.megablelib.enums.MegaBleBattery
import io.mega.megablelib.model.MegaBleDevice
import io.mega.megablelib.model.bean.*
import io.mega.megableparse.MegaPrBean
import io.mega.megableparse.MegaSpoPrBean
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.zjw.testblelib.util.FileUtil
import io.zjw.testblelib.util.Filtfilt
import io.zjw.testblelib.util.SendData
import io.zjw.testblelib.util.UploadUtil
import kotlinx.android.synthetic.main.activity_main.*
import no.nordicsemi.android.dfu.DfuServiceInitiator
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.concurrent.fixedRateTimer
import kotlin.concurrent.thread


@Logger(tag = "MainActivity", level = LoggerLevel.INFO)
class MainActivity : AppCompatActivity(), View.OnClickListener, OnChooseTimeListener {
    companion object {
        private const val TAG = "MainActivity"
        private const val SCAN_PERIOD: Long = 5
        private const val EVENT_CONNECTED = 10000
        private const val EVENT_DISCONNECTED = 10001
        private const val EVENT_CONNECTING = 10002
        private const val EVENT_SERVICECONNECTED = 1
        private const val EVENT_SERVICEDISCONNECTED = 0
        private const val REQUEST_ENABLE_BT = 10002
        private const val REQUEST_ACCESS_COARSE_LOCATION = 2
        private const val EVENT_RECEIVE_STOP_COMMAND = 3
        private var sendStopCommand = true
        private var serverIP = ""
        private var serverPort = "80"
        private var pluseOn = false
        //是否已连接
        private var isConnect = false
        //是否打开脉诊
        private var  isConnectOpen = false
        //图表---zzf
        //环境配置，当env = KJB时候，需要给服务器端实时推送数据
        private var env = ""
        private val kjbData = ConcurrentLinkedQueue<Int>()
        private var thread: Thread? = null
//        private var dataInt :Int=0;
        //图表---zzf

//        图表---zzf
            private var dynamicLineChartManager1: DynamicLineChartManager? = null

        //    private DynamicLineChartManager dynamicLineChartManager2;
//        private val list: MutableList<Int> = ArrayList() //数据集合
        private val list :Queue<Int> = LinkedList<Int>()
        private val names: MutableList<String> = ArrayList() //折线名字集合集合
        val dataOneSecond: ArrayList<Double> = ArrayList() //一秒内的数据
        private val colour: MutableList<Int> = ArrayList() //折线颜色集合
        val listData: MutableList<Int> = ArrayList() //数据集合
        private var userName =""
        @RequiresApi(Build.VERSION_CODES.O)
        private val formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
        private var fileName = ""
        private var phoneNumber = ""
        var fos: FileOutputStream? =null
        private var filePath = ""
        private var socketCallBack: SocketCallBack? = null
    }

    private val handler = Handler(Handler.Callback { msg: Message ->
        when (msg.what) {
            EVENT_CONNECTED -> {
                val bundle = msg.data
                val device = bundle.getSerializable("device") as MegaBleDevice
                setMegaDeviceInfo(device)
            }
            EVENT_DISCONNECTED -> {
                clearMegaDeviceInfo()
            }
            EVENT_CONNECTING -> {
                setConnectStatus()
            }
            EVENT_SERVICECONNECTED -> {
                setServiceConnectStatus()
            }
            EVENT_SERVICEDISCONNECTED -> {
                setServiceDisConnectStatus()
            }
            99999 -> {
//                Toast.makeText(this, "文件"+ fileName+"上传："+msg.obj, Toast.LENGTH_SHORT).show()
//                Toast.makeText(this, "文件" + fileName + "上传：" + msg.obj, Toast.LENGTH_LONG).show();
                val builder = AlertDialog.Builder(this)
                builder.setTitle("提示")
                builder.setMessage("源文件上传已完成")
                builder.setPositiveButton("确定",null)
                builder.show()
            }
            EVENT_RECEIVE_STOP_COMMAND -> {
                btn_pulse_off.performClick()
            }
            else -> {
            }
        }
        true
    })

    private  var  myClient : MyClient?=null
    private var  dataJson : JSONObject?=null
    // ui
    private var mScannedAdapter: ScannedAdapter? = null
    // permission checker
    private var mRequestPermissionHandler: RequestPermissionHandler? = null
    // ble
    private var mBluetoothAdapter: BluetoothAdapter? = null
    private val mScannedDevices: MutableList<ScannedDevice> = ArrayList()

    // sdk ble
    private var mDfuPath: String? = null
    private var megaBleClient: MegaBleClient? = null
    private var megaBleDevice: MegaBleDevice? = null
    private lateinit var infoDialog: AlertDialog
    private var periodTime = 0L
    private lateinit var timer:Timer
    private lateinit var starTimer:Timer
    private lateinit var sendDataTimer1:Timer
    private var sendStr :String?=null
    private val mLeScanCallback = LeScanCallback { device: BluetoothDevice, rssi: Int, scanRecord: ByteArray ->
        if (device.name == null) return@LeScanCallback
        // 过滤掉了设备名称中不含ring的设备，请看情况使用
        if (!device.name.toLowerCase().contains("ring")&& device.name != "MR") return@LeScanCallback
        // 戒指设备广播scanRecord的长度为62
        if (scanRecord.size < 62) return@LeScanCallback
        // 解析广播事例，先解析3代戒指广播
        val advOnly = MegaAdvParse.parse(scanRecord)
        if (advOnly == null) { // 不行了再解析2代戒指广播
            val advEntity = MegaBleClient.parseScanRecord(device, scanRecord)
            if (advEntity != null) Log.d(TAG, advEntity.toString())
        } else {
            Log.d(TAG, advOnly.toString())
        }
        val scannedDevice = ScannedDevice(device.name, device.address, rssi)
        Log.d(TAG, "device: $scannedDevice")
        val i = mScannedDevices.indexOf(scannedDevice)
        if (i == -1) {
            mScannedDevices.add(scannedDevice)
        } else {
            mScannedDevices[i].rssi = rssi
        }
    }
    private val megaBleCallback: MegaBleCallback = object : MegaBleCallback() {
        override fun onConnectionStateChange(connected: Boolean, device: MegaBleDevice?) {
            Log.d(TAG, "onConnectionStateChange: $connected")
            if (connected) {
                megaBleDevice = device
                sendToHandler(device)
                isConnect = false
            } else {
               // NLogger.i("megaBleDevice",megaBleDevice.toString())
                NLogger.i("megaBleDevice", "断开服务")
                handler.sendEmptyMessage(EVENT_DISCONNECTED)
                isConnect = true
                if (pluseOn){
                    isConnectOpen = true
                }
            }
        }



        override fun onError(code: Int) {
            NLogger.e(TAG, "Error code: $code")
        }

        override fun onStart() {
            val userId = "5837288dc59e0d00577c5f9a" // 12 2 digit hex strings, total 24 length


            val token = UtilsSharedPreference.get(this@MainActivity, UtilsSharedPreference.KEY_TOKEN)
            runOnUiThread { et_token!!.setText(token) }
            if (TextUtils.isEmpty(token)) {
//                megaBleClient!!.startWithoutToken(userId, megaBleDevice!!.mac)
                // 下面的方法更易用
                megaBleClient!!.startWithToken(userId, "0,0,0,0,0,0")
            } else {
                megaBleClient!!.startWithToken(userId, token)
            }
        }

        override fun onDeviceInfoReceived(device: MegaBleDevice) {
            // 提前获取电池电量、监测模式；在此处调用，可以在idle之前获得
            // 方便在idle后判断该做什么事
            megaBleClient!!.getV2Batt()
            megaBleClient!!.getV2Mode()
            //Log.d(TAG, "onDeviceInfoReceived $device")
            megaBleClient!!.enableV2ModeSpoMonitor(true)
            sendToHandler(device)
        }

        // default setting. Use this default value is ok.
        // 强制设置用户身体信息，请使用默认值即可，不用更改
        override fun onSetUserInfo() {
            megaBleClient!!.setUserInfo(25.toByte(), 1.toByte(), 170.toByte(), 60.toByte(), 0.toByte())
        }

        override fun onIdle() {
            // 设备闲时，可开启实时、开启长时监控、收监控数据。
            // 长时监控数据会被记录到戒指内部，实时数据不会。
            // 长时监控开启后，可断开蓝牙连接，戒指将自动保存心率血氧数据，以便后续手机连上收取。默认每次连上会同步过来。
            // 绑定token有变动时，用户信息，监测数据将被清空。
            // 建议默认开启全局实时通道，无需关闭，重复开启无影响
            // suggested setting, repeated call is ok.
            Log.d(TAG, "Important: the remote device is idle.")
            megaBleClient!!.toggleLive(true)
        }

        // default setting
//        override fun onEnsureBindWhenTokenNotMatch() {
//            megaBleClient!!.ensureBind(true)
//        }

        // 血氧实时模式、脉诊模式共用此回调
        @RequiresApi(Build.VERSION_CODES.O)
        override fun onV2LiveSpoLive(live: MegaV2LiveSpoLive) {

        }

        // 实时血氧仪模式的回调
        override fun onV2LiveSpoMonitor(live: MegaV2LiveSpoMonitor) {
            //Log.i("------","实时血氧仪模式的回调")
            when (live.status) {
                MegaBleConst.STATUS_LIVE_VALID -> {
                    updateV2Live(live)
                }
                MegaBleConst.STATUS_LIVE_PREPARING -> {
                    updateV2Live(live)
                }
                MegaBleConst.STATUS_LIVE_INVALID -> {
                    updateV2Live(live)
                }
            }
        }

        override fun onV2LiveSport(live: MegaV2LiveSport) {
            //Log.i("----------------","血氧")
            when (live.status) {
                MegaBleConst.STATUS_LIVE_VALID -> {
                    updateV2Live(live)
                }
                MegaBleConst.STATUS_LIVE_PREPARING -> {
                    updateV2Live("$live(preparing)")
                }
                MegaBleConst.STATUS_LIVE_INVALID -> {
                    updateV2Live("$live(invalid)")
                }
            }
        }

        // 请提示用户：敲击、晃动戒指
        // show user a window to shaking, in order to bind the ring
        // if token is matched (bind success), this step will be skipped
        override fun onKnockDevice() {
            //Log.d(TAG, "onKnockDevice!!!")
            runOnUiThread {
                val alertDialog = AlertDialog.Builder(this@MainActivity).create()
                alertDialog.setTitle("初始化")
                alertDialog.setMessage("请轻轻晃动戒指以完成链接")
                alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "关闭"
                ) { dialog: DialogInterface, which: Int -> dialog.dismiss() }
                alertDialog.show()
            }
        }

        // 绑定成功得到token, 下次用token验证匹配无需再敲击
        // get token when bind success, next time start with this token
        override fun onTokenReceived(token: String) {
            //Log.d(TAG, "onTokenReceived: $token")
            runOnUiThread { et_token!!.setText(token) }
            UtilsSharedPreference.put(this@MainActivity, UtilsSharedPreference.KEY_TOKEN, token)
        }

        override fun onRssiReceived(rssi: Int) {
            //Log.d(TAG, "onRssiReceived: $rssi")
            runOnUiThread { tv_rssi!!.text = rssi.toString() }
        }

        // 重要
        override fun onBatteryChanged(value: Int, status: Int) {
            runOnUiThread {
                // 请使用MegaBleBattery来判断电池状态，充电中可以收数据，但不能做监测相关动作
                // 请随时响应电池状态改变
                // normal(0, "normal"),
                // charging(1, "charging"),
                // full(2, "full"),
                // lowPower(3, "lowPower");
                // error(4, "error");
                // shutdown(5, "shutdown");
                tv_batt!!.text = value.toString()
                tv_batt_status!!.text = MegaBleBattery.getDescription(status)
                when (status) {
                    MegaBleBattery.charging.ordinal -> { /* todo */
                    }
                    MegaBleBattery.normal.ordinal -> { /* todo */
                    }
                    MegaBleBattery.lowPower.ordinal -> { /* todo */
                    }
                    MegaBleBattery.full.ordinal -> { /* todo */
                    }
                }
            }
        }

        override fun onV2ModeReceived(mode: MegaV2Mode) {
            when (mode.mode) {
                MegaBleConst.MODE_MONITOR -> {
                    // 正处于血氧长时监测模式
                }
                MegaBleConst.MODE_LIVE -> {
                    // 正处于监测实时监测模式
                }
                MegaBleConst.MODE_SPORT -> {
                    // 正处于运动模式
                }
                MegaBleConst.MODE_PULSE -> {
                    // 正处于脉诊模式

                }
            }
        }

        /**
         * 固件升级
         * dfu 库使用参考
         * https://github.com/NordicSemiconductor/Android-DFU-Library/tree/release/documentation
         */
        override fun onReadyToDfu() {
            // if不写的话，在高版本的系统上可能会有问题
            // 另行定义方法，接收mac, name, path也可；发送消息给升级页面也可。这里就直接写在回调里了
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                DfuServiceInitiator.createDfuNotificationChannel(this@MainActivity)
            }
            val starter = DfuServiceInitiator(megaBleDevice!!.mac)
                    .setDeviceName(megaBleDevice!!.name) // onDfuBleConnectionChange里device赋值的原因，这里要用
                    .setKeepBond(false)
                    .setZip(mDfuPath!!)
            starter.setDisableNotification(true) // 禁止notification的交互
//            starter.start(this@MainActivity, DfuService::class.java)
        }

        override fun onSyncDailyDataComplete(bytes: ByteArray?) {
            Log.d(TAG, "onSyncDailyDataComplete: " + bytes?.contentToString())
            var result = megaBleClient!!.parseDailyEntry(bytes)
            Log.d(TAG, "$result")
            runOnUiThread { Toast.makeText(this@MainActivity, "parse success", Toast.LENGTH_SHORT).show() }
        }

        override fun onSyncNoDataOfDaily() {
            Log.d(TAG, "no daily data")
        }

        override fun onSyncMonitorDataComplete(bytes: ByteArray?, dataStopType: Int, dataType: Int, uid: String?, steps: Int) {
            Log.d(TAG, "onSyncMonitorDataComplete: " + bytes?.contentToString())
            Log.d(TAG, "uid: $uid")
            Log.d(TAG, "dataType: $dataType")
            Log.d(TAG, "parseVersion:${MegaBleClient.megaParseVesrion()}")
            when (dataType) {
                MegaBleConst.MODE_MONITOR -> {
                    megaBleClient!!.parseSpoPr(bytes, parseSpoPrResult)
                }
                MegaBleConst.MODE_SPORT -> {
                    megaBleClient!!.parseSport(bytes, parsePrResult)
                }
                else -> {
                }
            }
        }

        override fun onSyncNoDataOfMonitor() {
            Log.d(TAG, "no data")
        }



        override fun onHeartBeatReceived(heartBeat: MegaBleHeartBeat) {
           // NLogger.i("心跳检测", "$heartBeat")
            if ( isConnectOpen){
                megaBleClient!!.enableV2ModePulse(false)//关闭脉诊
                megaBleClient!!.disableRawdata()//关闭rawdata
                Thread.sleep(1000)
                megaBleClient!!.enableV2ModePulse(true)//开启脉诊
                val rawdataConfig = MegaRawdataConfig(true, false, serverIP, 54378)
                megaBleClient!!.enableRawdataPulse(rawdataConfig)
                pluseOn = true
                isConnectOpen = false
            }

        }
        @RequiresApi(Build.VERSION_CODES.O)
        override fun onRawdataParsed(a: Array<out IntArray>?) {
            if (a != null) {

                for (i in a.indices) {
                    //TODO 文件记录
//                    var data = a[i][0].toString()
                    FileUtil.addFile(filePath + fileName, a[i][0].toString())
                    //KJB 将数据放入队列
                    if(env == "KJB"){
                        kjbData.add(a[i][0])
                    }
//                    dynamicLineChartManager1!!.addEntry(a[i][0])
//                    list.add(a[i][0])
                    if(list.size==500){
                        list.poll()
                    }
                    list.add(a[i][0])
                }

            }
        }
        override fun onV2PeriodSettingReceived(setting: MegaV2PeriodSetting?) {
            Log.i(TAG, "onV2PeriodSettingReceived:$setting")
        }

    }

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val intent = intent
        serverIP = intent.getStringExtra("serverIP")
        env = intent.getStringExtra("env")
        phoneNumber = intent.getStringExtra("phoneNumber")
        userName = intent.getStringExtra("userName")
        setContentView(R.layout.activity_main)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        mRequestPermissionHandler = RequestPermissionHandler()
        tv_userInfo.text = phoneNumber
//        scanServerIp()
        var url = "ws://$serverIP:54378/ws";
        myClient = object : MyClient(url) {
            override fun onMessage(message: String?) {
                super.onMessage(message)
                Log.i("myclient-onMessage",message)
                if(message == "PULSE-STOP" && pluseOn){
                    sendStopCommand = false
                    handler.sendEmptyMessage(EVENT_RECEIVE_STOP_COMMAND);
                }else if(message == "PULSE-START" && !pluseOn){
                    btn_pulse_on.performClick()
                }

            }
        }
        (myClient as MyClient).connectBlocking();
        NLogger.i(applicationContext.filesDir.path)
        //checkAppPermission()
        initView()
        initBle()
        // mock id, key，use yours
        megaBleClient = MegaBleBuilder()
                .withSecretId("D4CE5DD515F81247")
                .withSecretKey("uedQ2MgVEFlsGIWSgofHYHNdZSyHmmJ5")
                .withContext(this)
                .withCallback(megaBleCallback)
                .build()
        // 开发测试时，可以开启debug
        megaBleClient!!.setDebugEnable(true)
        startTimer()
//        KJB 发送数据
        if(env=="KJB"){
            sendDataTimer()
        }
        //图表---zzf

//        lineChart = findViewById<View>(R.id.data_chart) as LineChart
//
//        //折线名字
//        names.add("实时脉搏")
//        //折线颜色
//        colour.add(Color.BLUE)
//        dynamicLineChartManager = DynamicLineChartManager1(lineChart, names, colour)
//        dynamicLineChartManager!!.setYAxis(40000f, 28000f, 10)
//        dynamicLineChartManager!!.setDescription("")

//        dynamicLineChartManager!!.setHightLimitLine(40000.0f, "max", Color.RED)
//        dynamicLineChartManager!!.setLowLimitLine(20000, "min", Color.GREEN)

//        force[0] = 100f
//        if (thread == null) createThread()
        //图表---zzf
//图表---zzf
        val mChart1 = findViewById<View>(R.id.dynamic_chart1) as LineChart
//        LineChart mChart2 = (LineChart) findViewById(R.id.dynamic_chart2);
        //折线名字
        //        LineChart mChart2 = (LineChart) findViewById(R.id.dynamic_chart2);
        //折线名字
        names.add("实时脉搏")
        //折线颜色
        colour.add(Color.BLUE)
        colour.add(Color.GREEN)
        colour.add(Color.CYAN)
        dynamicLineChartManager1 = DynamicLineChartManager(mChart1, "实时脉搏", Color.BLUE)
        dynamicLineChartManager1!!.setYAxis(160f, 40f, 8)
        dynamicLineChartManager1!!.setDescription("脉搏")
    //        //死循环添加数据
        Thread {
            var duration = 0
            while (true) {
                try {
                    if(pluseOn){
                        btn_pulse_on.text = String.format("%02d:%02d", duration/60, duration%60)
                        duration += 1
                        Thread.sleep(1000)
                            runOnUiThread {
                                val size = list.size;

                                    for (i in 0 until size){
                                        if(list.size>0){
                                            var data  = list.poll()

//                                            var  data = list.elementAt(i)
//                                            if(listData.size==500){
//                                                listData.removeAt(0)
//                                                if(data !=null){
//                                                    listData.add((data * -1).toDouble())
//                                                }
//                                            }else{
//                                                if(data !=null){
//                                                    listData.add((data * -1).toDouble())
//                                                }
//                                            }
                                            if(data != null){
//                                                Log.i("data---",data.toString())
//                                                dataOneSecond.add((data*-1).toDouble())
                                                data *= -1
                                                dataOneSecond.add((data).toDouble())
                                            }
                                        }
                                    }
                                //巴特沃斯滤波器进行数据转换
//                                    listData = ButtonWorthFilter.buttonWorth(listData)

//                                var dataArray = ButtonWorthFilter.buttonWorth(dataOneSecond.toDoubleArray())

//                                if (env.equals("KJB")){
//                                    SendData.sendData(dataOneSecond, serverIP, env)
//                                }
                                var dataArray = Filtfilt.doBandFilter(dataOneSecond)
                                for (item in dataArray){
                                    if(listData.size==500){
                                                listData.removeAt(0)
                                                if(item !=null){
                                                    listData.add(item.toInt())
                                                }
                                            }else{
                                                if(item !=null){
                                                    listData.add(item.toInt())
                                                }
                                            }
                                }
                                if(listData.isNotEmpty()){
                                    var maxnum = listData[0]
                                    var minnum = listData[0]
//                                    Log.i("dataArray.size---", listData.size.toString())
                                    for (item in listData){
                                        if(maxnum < item ){
                                            maxnum = item+100
                                        }
                                        if(minnum > item){
                                            minnum = item-100
                                        }
                                    }
//                                    Log.i("maxNum", "maxNum=$maxnum")
//                                    Log.i("minNum", "minNum=$minnum")

                                    for(i in 0 until listData.size){
                                        dynamicLineChartManager1!!.setYAxis(maxnum.toFloat(), minnum.toFloat(), 5)
//                                        dynamicLineChartManager1!!.setYAxis(1000F, -1000F, 5)

                                        dynamicLineChartManager1!!.addEntry(listData[i])
                                    }
                                    if (!pluseOn) {
                                        duration = 0
                                    }
                                }
                            }
                        }

                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        }.start()

    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun sendDataTimer(){
        sendDataTimer1 = fixedRateTimer("sendData",false,100,500){
                if(kjbData.size>0){
                    var jsonArray  = JSONArray()
                    for(i in 0 until kjbData.size){
                        val aa =kjbData.poll()
                        jsonArray.add(aa)
                    }
                    Log.i("jsonArray.size--",jsonArray.size.toString())
                    SendData.sendData(jsonArray, serverIP, env,myClient)
                }
        }
    }


    private fun startTimer() {
        starTimer = fixedRateTimer("", false, 0, 10000) {
            if (isConnect){
                try {
                    handler.sendEmptyMessage(EVENT_CONNECTING)
                    megaBleClient !!.connect(megaBleDevice?.mac, megaBleDevice?.name)
                    megaBleClient!!.enableV2ModeSpoMonitor(true)
                }catch (_: Exception){

                }
            }
            serviceCheck()
        }
    }

    private fun serviceCheck() {
//        val  result = ServerUtil.isPortUseful(serverIP, 54378, 500)
        var port = 8082
        if (env == "ZB") {
            port = 8081
        }else if(env=="KJB"){
            port = 8086
        }else if (env == "ccy"){
            port = 8109
        }
        val result = ServerUtil.isPortUseful2(serverIP, port, 5000, env)
        if ( result){
            handler.sendEmptyMessage(EVENT_SERVICECONNECTED);
        }else{
            handler.sendEmptyMessage(EVENT_SERVICEDISCONNECTED);
        }

    }




    override fun onDestroy() {
        if(::infoDialog.isInitialized) {
            if (infoDialog.isShowing)
                infoDialog.dismiss()
        }
        if (chooseTimeDialog.isShowing)
            chooseTimeDialog.dismiss()
        if (megaBleClient != null) megaBleClient!!.disConnect()
        if(this::sendDataTimer1.isInitialized){
            sendDataTimer1.cancel()
        }
        //serviceTimer!!.cancel()
        isConnect = false
        pluseOn = false
        if (::timer.isInitialized){
            timer.cancel()
        }
        super.onDestroy()
    }


    private fun initView() {

        setSupportActionBar(toolbar)
        btn_scan.setOnClickListener(this)

        recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        LinearSnapHelper().attachToRecyclerView(recycler_view)
        mScannedAdapter = ScannedAdapter(mScannedDevices)
        recycler_view.adapter = mScannedAdapter
        btn_pulse_on.setOnClickListener(this)
        btn_pulse_off.setOnClickListener(this)
        button_auto_setup_server.setOnClickListener(this)
        iv_info.setOnClickListener(this)
        // get token form shardPreference
        et_token.setText(UtilsSharedPreference.get(this, UtilsSharedPreference.KEY_TOKEN))
        et_token.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                if (s != null) tv_clear.visibility = View.VISIBLE
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { //                if (s == null) tv_clear.setVisibility(View.INVISIBLE);
//                else tv_clear.setVisibility(View.VISIBLE);
            }

            override fun afterTextChanged(s: Editable) {
                if (s.isEmpty()) tv_clear.visibility = View.INVISIBLE
            }
        })
        findViewById<View>(android.R.id.content).setOnTouchListener { v, event ->
            if (this@MainActivity.currentFocus != null) {
                tv_clear.visibility = View.INVISIBLE
                et_token.clearFocus()
                val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                inputMethodManager.hideSoftInputFromWindow(this@MainActivity.currentFocus.windowToken, 0)
            }
            false
        }

        chooseTimeDialog = ChooseTimeDialog(this, this)
    }

    private fun initBle() {
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        mBluetoothAdapter = bluetoothManager.adapter
    }

    lateinit var chooseTimeDialog: ChooseTimeDialog


    @RequiresApi(Build.VERSION_CODES.O)
    override fun onClick(v: View) {
        if ( v.id != R.id.btn_scan
                && v.id != R.id.iv_info
                && R.id.tv_clear != v.id
                && v.id != R.id.btn_pulse_on
                && v.id != R.id.btn_pulse_off
                && v.id != R.id.button_auto_setup_server
                ) {
            if (megaBleDevice == null) {
                Toast.makeText(this, "ble offline", Toast.LENGTH_SHORT).show()
                return
            }
        }
        when (v.id) {
            R.id.btn_scan -> {
                if (PermissionChecker.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), REQUEST_ACCESS_COARSE_LOCATION)
                    com.yuanxu.ecg.L.d("====++request Permissions")
                    return
                }
                scanLeDevices()
            }

            // 开脉诊
            R.id.btn_pulse_on -> {
                if (megaBleDevice == null) {
                    infoDialog = AlertDialog.Builder(this)
                            .setTitle("错误：")
                            .setPositiveButton(R.string.ok, null)
                            .setMessage("请先连接设备")
                            .create()
                    infoDialog.show()

                    return
                }

                if (!pluseOn) {
                    //服务端是否连接成功
                    if (serverIP == null || serverIP.isEmpty()) {
                        infoDialog = AlertDialog.Builder(this)
                                .setTitle("错误：")
                                .setPositiveButton(R.string.ok, null)
                                .setMessage("请先连接服务器")
                                .create()
                        infoDialog.show()
                        return
                    }
                    megaBleClient!!.enableV2ModeSpoMonitor(false)
                    //如果脉诊已关闭，则开启，并开启Rawdata
                    megaBleClient!!.enableV2ModePulse(true)//开启脉诊
                    val rawdataConfig = MegaRawdataConfig(false, false, serverIP, 54378)
                    megaBleClient!!.enableRawdataPulse(rawdataConfig)
                    megaBleClient!!.enableRawdataSpo(rawdataConfig)
                    Toast.makeText(this, "已开启脉诊", Toast.LENGTH_SHORT).show()
                    pluseOn = true
                    btn_pulse_off.isEnabled = true
                    //创建文件
                    filePath = this.applicationContext.filesDir.path + "/脉诊/"
                    val current = LocalDateTime.now();
                    var currentTime = current.format(formatter)

//                    if (fileName == "") {
//                        fileName = "脉诊-" + userName + "-" + phoneNumber + "-" + currentTime + ".txt"
//                    }
                    fileName = "脉诊-"+ userName +"-"+ phoneNumber+"-"+currentTime+".txt"

//                    //保存数据，输入用户信息
//                    val builder = AlertDialog.Builder(this)
//                    val editTextUserName = EditText(this)
//                    editTextUserName.setText(userName)
//                    builder.setView(editTextUserName)
//                    builder.setTitle("请输入您的手机号")
//                    builder.setPositiveButton("确定") { dialog, which ->
//                        userName = editTextUserName!!.text.toString()
//                        //验证用户信息
//                        var checkUser = false;
//                        val url = "http://"+ serverIP+":8081/user/"+ userName+"/checkUser"
//                        Log.i(TAG,"url--"+url)
//                        Thread {
//                            try {
//                                Log.i("httpUtil",HttpUtil.httpGet(url))
//                                checkUser = HttpUtil.httpGet(url).equals("1")
//
//
//                            } catch (e: java.lang.Exception) {
//                                e.printStackTrace()
//                            }
//                        }.start()
//                        Thread.sleep(500)
//                        Log.i("checkUser",checkUser.toString())
//                        if(!checkUser){
//                            infoDialog = AlertDialog.Builder(this)
//                                    .setTitle("错误：")
//                                    .setPositiveButton(R.string.ok, null)
//                                    .setMessage("请先注册！")
//                                    .create()
//                            infoDialog.show()
//                            return@setPositiveButton
//                        }
//
//
//                        megaBleClient!!.enableV2ModeSpoMonitor(false)
//                        //如果脉诊已关闭，则开启，并开启Rawdata
//                        megaBleClient!!.enableV2ModePulse(true)//开启脉诊
//                        val rawdataConfig = MegaRawdataConfig(false, false, "", 0)
//                        megaBleClient!!.enableRawdataPulse(rawdataConfig)
//                        megaBleClient!!.enableRawdataSpo(rawdataConfig)
//                        Toast.makeText(this, "已开启脉诊", Toast.LENGTH_SHORT).show()
//                        btn_pulse_on.text = "关脉诊"
//                        pluseOn = true
//                        //创建文件
//                        filePath = this.getApplicationContext().getFilesDir().getPath() + "/脉诊/"
//                        val current = LocalDateTime.now();
//                        var currentTime = current.format(formatter)
//                        if (fileName == "") {
//                            fileName = "脉诊"+userName + "-" + currentTime + ".txt"
//                        }
//                    }
//                    builder.show()
                }

            }

            // 关脉诊
            R.id.btn_pulse_off -> {
                if (megaBleDevice == null) {
                    infoDialog = AlertDialog.Builder(this)
                        .setTitle("错误：")
                        .setPositiveButton(R.string.ok, null)
                        .setMessage("请先连接设备")
                        .create()
                    infoDialog.show()

                    return
                }

                //如果脉诊已开启，则关闭脉诊，并关闭Rawdata
                if (pluseOn) {
                    megaBleClient!!.enableV2ModePulse(false)//关闭脉诊
                    megaBleClient!!.disableRawdata()//关闭rawdata
                    if(env == "KJB" && sendStopCommand){
                        SendData.sendData("PULSE-STOP", serverIP, "$env-PULSE-STATE",myClient)
                    }
                    sendStopCommand = true
                    Toast.makeText(this, "已关闭脉诊", Toast.LENGTH_SHORT).show()
                    pluseOn = false
                    btn_pulse_off.isEnabled = false
                    btn_pulse_on.text = resources.getString(R.string.label_enable_pulse)
                    //上传文件
//                    Toast.makeText(this, "开始上传文件", Toast.LENGTH_SHORT).show()
//                    Toast.makeText(this, "开始上传文件数据文件，请稍后", Toast.LENGTH_LONG).show()
                    if(env != "KJB"){
                        val builder = AlertDialog.Builder(this)
                        builder.setTitle("提示")
                        builder.setMessage("点击上传按钮上传数据文件")
                        builder.setPositiveButton("上传") { dialog, which ->
                            Log.i("fileName----", fileName)
                            if (fileName != "") {
                                var floder = File(this.applicationContext.filesDir.path + "/脉诊/")
                                if (!floder.exists()) {
                                    floder.mkdirs()
                                }
                                var dataFile = File(floder, fileName)
                                var jsonObject: com.alibaba.fastjson.JSONObject = com.alibaba.fastjson.JSONObject()
                                jsonObject.put("file", dataFile)
                                var port = 8082
                                if(env == "ZB"){
                                    port = 8081
                                }else if (env == "ccy"){
                                    port = 8109
                                }
                                val url = "http://$serverIP:$port/file/uploadData"
                                Thread {
                                    try {
                                        val result = UploadUtil.getInstance().upload(url, dataFile)
                                        Log.i(" UploadUtil.---", result.toString())
                                        val message = Message()
                                        message.what = 99999
                                        message.obj = result
                                        handler.sendMessage(message)
                                        Thread.sleep(1500)
                                    } catch (e: java.lang.Exception) {
                                        e.printStackTrace()
                                    }
                                }.start()
                            } }
                        builder.setNeutralButton("取消", null)
                        builder.show()
                    }

                }
            }

            R.id.tv_clear -> {
                et_token!!.text = null
                UtilsSharedPreference.remove(this, UtilsSharedPreference.KEY_TOKEN)
            }

            R.id.button_auto_setup_server -> {
                thread {
                    kotlin.run {
                        NLogger.i(TAG, "开始扫描服务器")
                        ServerUtil.changeOpenState(this)
                        val str = ServerUtil.setUpServer(this, env)
                        if (str.trim().isEmpty()) {
                            Looper.prepare()
                            infoDialog = AlertDialog.Builder(this)
                                    .setTitle("错误：")
                                    .setPositiveButton(R.string.ok, null)
                                    .setMessage("连接服务器超时请联系管理员")
                                    .create()
                            infoDialog.show()
                            Looper.loop()
                        } else {
                            serverIP = str;
                            Looper.prepare()
                            infoDialog = AlertDialog.Builder(this)
//                                .setTitle("错误：")
                                    .setPositiveButton(R.string.ok, null)
                                    .setMessage("服务器连接成功")
                                    .create()
                            infoDialog.show()
                            Looper.loop()
                        }
                    }
                }

            }
            R.id.iv_info -> {
                try {
                    val versionName = packageManager.getPackageInfo(this.packageName, 0).versionName
                    tv_version.text = "v$versionName"
                    var message = String.format(getString(R.string.info_content), versionName, MegaBleClient.megaParseVesrion(), serverIP)
                    infoDialog = AlertDialog.Builder(this)
                            .setTitle(R.string.info_title)
                            .setPositiveButton(R.string.ok, null)
                            .setMessage(message)
                            .create()
                    infoDialog.show()
                } catch (e: PackageManager.NameNotFoundException) {
                    e.printStackTrace()
                }
            }
            else -> {
            }
        }
    }

    @SuppressLint("CheckResult")
    private fun scanLeDevices() {
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "ble not support", Toast.LENGTH_SHORT).show()
            return
        }
        val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val statusOfGPS = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        if (!statusOfGPS) {
            Toast.makeText(this, "GPS disable, plz enable", Toast.LENGTH_SHORT).show()
            return
        }
        if (!mBluetoothAdapter!!.isEnabled) {
            val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
            L.d("====++enable ble")
            return
        }
        mScannedDevices.clear()
        mScannedAdapter!!.notifyDataSetChanged()
        btn_scan!!.isClickable = false
        Observable.timer(SCAN_PERIOD, TimeUnit.SECONDS).subscribe { aLong: Long? ->
            mBluetoothAdapter!!.stopLeScan(mLeScanCallback)
            btn_scan!!.isClickable = true
        }
        mBluetoothAdapter!!.startLeScan(mLeScanCallback)
        Observable.interval(1, TimeUnit.SECONDS)
                .take(SCAN_PERIOD)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { aLong: Long ->
                    Log.d(TAG, aLong.toString() + "scaning...")
                    mScannedAdapter!!.notifyDataSetChanged()
                }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        L.d("====++activity result $requestCode $resultCode $data")
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
        } else if (requestCode == REQUEST_ENABLE_BT) {
        scanLeDevices()
        }
    }



    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        L.d("====++Permissions result $requestCode $permissions $grantResults")
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        mRequestPermissionHandler!!.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

    internal inner class ScannedAdapter(private val mList: List<ScannedDevice>) : RecyclerView.Adapter<ScannedViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScannedViewHolder {
            val view = LayoutInflater.from(this@MainActivity).inflate(R.layout.item_scan_result, parent, false)
            return ScannedViewHolder(view)
        }

        override fun onBindViewHolder(holder: ScannedViewHolder, position: Int) {
            val device = mList[position]
            holder.bindView(device)
        }

        override fun getItemCount(): Int {
            return mList.size
        }

    }

    internal inner class ScannedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val v: CardView = itemView as CardView
        private val tvName: TextView
        private val tvAddress: TextView
        private val tvRssi: TextView

        init {
            tvName = v.findViewById(R.id.tv_name)
            tvAddress = v.findViewById(R.id.tv_mac)
            tvRssi = v.findViewById(R.id.tv_rssi)
        }

        fun bindView(device: ScannedDevice) {
            tvName.text = device.name
            tvAddress.text = device.address
            tvRssi.text = device.rssi.toString()
            v.setOnClickListener { v: View? ->
//                Toast.makeText(this@MainActivity, "Connecting -> " + device.name + " " + device.address, Toast.LENGTH_SHORT).show()
                Toast.makeText(this@MainActivity, "正在连接设备 " + device.name + " " + device.address, Toast.LENGTH_SHORT).show()

                try {
                    megaBleClient!!.connect(device.address, device.name)
                }catch (e: Exception){

                }
            }
        }
    }

    /**
     * set UI
     */
    @SuppressLint("ResourceType")
    private fun setMegaDeviceInfo(device: MegaBleDevice) {
        try {
            main_content.visibility = View.VISIBLE
            tv_name.text = device.name
            tv_mac.text = device.mac
            tv_fw_version.text = device.fwVer
            tv_sn.text = device.sn
            //tv_other_info.text = device.otherInfo
            tv_device_status.text = "已连接"
            tv_device_status.setTextColor(Color.parseColor(getString(R.color.green)));
        }catch (e: Exception){
            NLogger.e("set UI", e.printStackTrace().toString())
        }
    }

    @SuppressLint("ResourceType")
    private fun setConnectStatus() {
        try {
            tv_device_status.text = "正在重新连接"
            tv_device_status.setTextColor(Color.parseColor(getString(R.color.black)));
        }catch (e: Exception){
            NLogger.e("set UI", e.printStackTrace().toString())
        }
    }
    @SuppressLint("ResourceType")
    private fun setServiceConnectStatus() {
        try {
            serviceStatus.text = "已连接"
            serviceStatus.setTextColor(Color.parseColor(getString(R.color.green)));
        }catch (e: Exception){
            NLogger.e("set UI", e.printStackTrace().toString())
        }
    }
    @SuppressLint("ResourceType")
    private fun setServiceDisConnectStatus() {
        try {
            serviceStatus.text = "未连接"
//            tv.getPaint().setStyle(Paint.Style.FILL_AND_STROKRE),tv.getPaint().setStrokeWidth(0.7)
//            serviceStatus.paint.style=Paint.Style.FILL_AND_STROKE
//            serviceStatus.paint.strokeWidth = 0.7F
            serviceStatus.setTextColor(Color.parseColor(getString(R.color.black)));
        }catch (e: Exception){
            NLogger.e("set UI", e.printStackTrace().toString())
        }
    }

    @SuppressLint("ResourceType")
    private fun clearMegaDeviceInfo() {
        tv_name.text = null
        tv_mac.text = null
        tv_fw_version.text = null
        tv_sn.text = null
        tv_device_status.text = "未连接"
        tv_device_status.setTextColor(Color.parseColor(getString(R.color.black)));
        //tv_other_info.text = null
        tv_batt.text = null
        tv_batt_status.text = null
        tv_rssi.text = null
        tv_spo.text = null
        tv_hr.text = null
        tv_live_desc.text = null
//        tv_sync_progress.text = null
        et_token.text = null
        //megaBleDevice = null
    }

    private fun sendToHandler(device: MegaBleDevice?) {
        val msg = Message.obtain()
        msg.what = EVENT_CONNECTED
        val bundle = Bundle()
        bundle.putSerializable("device", device)
        msg.data = bundle
        handler.sendMessage(msg)

    }

    private fun <T> updateV2Live(live: T) {
        runOnUiThread {
            //Log.i("---",live.toString())
            //tv_v2_live!!.text = live.toString()
            var  megaV2LiveSpoMonitor : MegaV2LiveSpoMonitor=live as MegaV2LiveSpoMonitor
            //Log.i("---",megaV2LiveSpoMonitor.toString())
            tv_spo!!.text = megaV2LiveSpoMonitor.spo.toString()
            tv_hr!!.text = megaV2LiveSpoMonitor.pr.toString()
            // 使用AnimationUtils装载动画配置文件
            val animation = AnimationUtils.loadAnimation(this@MainActivity, R.anim.alpha)
            // 启动动画
            tv_smile!!.startAnimation(animation)
        }
    }




    @Throws(IOException::class)
    private fun readMockFromAsset(filename: String): ByteArray {
        val ins = resources.assets.open(filename)
        val bos = ByteArrayOutputStream()
        val buf = ByteArray(10 * 1024)
        var size: Int
        while (ins.read(buf).also { size = it } != -1) bos.write(buf, 0, size)
        ins.close()
        bos.flush()
        bos.close()
        return bos.toByteArray()
    }

    var parseSpoPrResult = object : MegaAuth.Callback<MegaSpoPrBean> {
        override fun onSuccess(p0: MegaSpoPrBean?) {
            Log.d(TAG, p0.toString())
            runOnUiThread { Toast.makeText(this@MainActivity, "parse success", Toast.LENGTH_SHORT).show() }
        }

        override fun onFail(p0: String?) {
            Log.d(TAG, p0)
            runOnUiThread { Toast.makeText(this@MainActivity, "auth failed", Toast.LENGTH_SHORT).show() }
        }
    }

    var parsePrResult = object : MegaAuth.Callback<MegaPrBean> {
        override fun onSuccess(p0: MegaPrBean?) {
            Log.d(TAG, p0.toString())
            runOnUiThread { Toast.makeText(this@MainActivity, "parse success", Toast.LENGTH_SHORT).show() }
        }

        override fun onFail(p0: String?) {
            Log.d(TAG, p0)
            runOnUiThread { Toast.makeText(this@MainActivity, "auth failed", Toast.LENGTH_SHORT).show() }
        }
    }

    class ChooseTimeDialog(context: Context, listener: OnChooseTimeListener) : BottomSheetDialog(context) {
        var timePicker: TimePicker? = null
        var calendar: Calendar = Calendar.getInstance()

        init {
            setContentView(R.layout.view_time_picker)
            timePicker = findViewById(R.id.time_picker)
            timePicker?.setIs24HourView(true)
            findViewById<Button>(R.id.btn_ok)?.setOnClickListener {
                listener.chooseTime(timePicker!!.currentHour, timePicker!!.currentMinute)
                dismiss()
            }
        }

        override fun show() {
            calendar.timeInMillis = System.currentTimeMillis()
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                timePicker?.currentHour = calendar.get(Calendar.HOUR_OF_DAY)
                timePicker?.currentMinute = calendar.get(Calendar.MINUTE)
            } else {
                timePicker?.hour = calendar.get(Calendar.HOUR_OF_DAY)
                timePicker?.minute = calendar.get(Calendar.MINUTE)
            }
            super.show()
        }
    }

    override fun chooseTime(hour: Int, minute: Int) {
        //NLogger.i(TAG, "$hour:$minute")
//        tv_time.text = "$hour:$minute"
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.SECOND, 0)
        calendar.set(Calendar.HOUR_OF_DAY, hour)
        calendar.set(Calendar.MINUTE, minute)
        periodTime = calendar.timeInMillis
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK){
            myClient?.close()
            megaBleClient!!.disConnect()
            //exitProcess(0)

        }
        return super.onKeyDown(keyCode, event)
    }


}


interface OnChooseTimeListener {

    fun chooseTime(hour: Int, minute: Int)
}